package com.xuecheng.manage_cms.service;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.xuecheng.framework.domain.cms.CmsConfig;
import com.xuecheng.framework.domain.cms.CmsPage;
import com.xuecheng.framework.domain.cms.CmsTemplate;
import com.xuecheng.framework.domain.cms.request.QueryPageRequest;
import com.xuecheng.framework.domain.cms.response.CmsCode;
import com.xuecheng.framework.domain.cms.response.CmsPageResult;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.framework.model.response.*;
import com.xuecheng.manage_cms.config.RabbitConfig;
import com.xuecheng.manage_cms.dao.CmsPageRepository;
import com.xuecheng.manage_cms.dao.CmsTemplateRepository;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.client.RestTemplate;


import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;

@Service
public class PageService {
    @Autowired
    private CmsPageRepository cmsPageRepository;
    //用于远程http请求 springMVC 的RestTemplate 底层用okhttpClient
    @Autowired
    private RestTemplate restTemplate;
    //用于访问mongoDB在db上存储的文件
    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Autowired
    private CmsTemplateRepository cmsTemplateRepository;
    //用于fs文件下载
    @Autowired
    private GridFSBucket gridFSBucket;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public QueryResponseResult findList(Integer page, Integer size, QueryPageRequest queryPageRequest) {

        if (queryPageRequest == null) {
            queryPageRequest = new QueryPageRequest();
        }
        if (page <= 0) {
            page = 1;
        }
        if (size <= 0) {
            size = 10;
        }
        page -= 1;

        CmsPage cmsPage = new CmsPage();
        if (!queryPageRequest.getPageAliase().isEmpty()) {
            cmsPage.setPageAliase(queryPageRequest.getPageAliase());
        }
        if (!queryPageRequest.getSiteId().isEmpty()) {
            cmsPage.setSiteId(queryPageRequest.getSiteId());
        }

        Pageable pageAble = PageRequest.of(page, size);
        ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains());
        Example<CmsPage> example = Example.of(cmsPage, matcher);
        Page<CmsPage> all = cmsPageRepository.findAll(example, pageAble);


        QueryResult queryResult = new QueryResult();
        queryResult.setList(all.getContent());
        queryResult.setTotal(all.getTotalElements());

        return new QueryResponseResult(CommonCode.SUCCESS, queryResult);
    }

    public QueryResponseResult findPageAliase(String siteId) {
        if (siteId == null || siteId.length() == 0) {
            return null;
        }
        List<CmsPage> bySiteId = cmsPageRepository.findBySiteId(siteId);
        List<String> list = new ArrayList<>();
        for (CmsPage cmsPage : bySiteId) {
            boolean merge = merge(cmsPage.getPageAliase(), list);
            if (merge) {
                list.add(cmsPage.getPageAliase());
            }

        }
        QueryResult queryResult = new QueryResult();
        queryResult.setList(list);
        queryResult.setTotal(bySiteId.size());
        return new QueryResponseResult(CommonCode.SUCCESS, queryResult);

    }


    //去重
    private <T> boolean merge(T str, List<T> list) {
        for (T o : list) {
            if (str.equals(o)) {
                return false;
            }
        }
        return true;
    }

    public CmsPageResult save(CmsPage cmsPage) {
        CmsPage cmsPageFind = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
        if (cmsPageFind == null) {
            cmsPage.setPageId(null);
            cmsPageRepository.save(cmsPage);
            return new CmsPageResult(CommonCode.SUCCESS, cmsPage);
        } else {
            return new CmsPageResult(CommonCode.FAIL, null);
        }

    }

    public CmsPageResult findById(String pageId) {
        Optional<CmsPage> byId = cmsPageRepository.findById(pageId);
        if (byId.isPresent()) {
            CmsPage cmsPage = byId.get();
            return new CmsPageResult(CommonCode.SUCCESS, cmsPage);

        } else {
            return null;
        }
    }

    public CmsPageResult update(String pageId, CmsPage cmsPage) {
        CmsPageResult byid = this.findById(pageId);
        CmsPage one = byid.getCmsPage();
        if (one != null) {
            one.setTemplateId(cmsPage.getTemplateId());
            one.setSiteId(cmsPage.getSiteId());
            one.setPageAliase(cmsPage.getPageAliase());
            one.setPageName(cmsPage.getPageName());
            //更新访问路径    
            one.setPageWebPath(cmsPage.getPageWebPath());
            //更新物理路径     
            one.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
            CmsPage save = cmsPageRepository.save(one);
            return new CmsPageResult(CommonCode.SUCCESS, save);
        } else {
            return null;
        }
    }

    public ResponseResult delById(String id) {

        CmsPageResult byId = this.findById(id);

        if (byId.getCmsPage() != null) {

            cmsPageRepository.delete(byId.getCmsPage());
            return new ResponseResult(CommonCode.SUCCESS);
        } else {
            return new ResponseResult(CommonCode.FAIL);
        }
    }

    //获取模板与模型数据生成的html的String数据
    public String getPageHtml(String pageId) {
        //获取模型数据
        Map model = getModel(pageId);

        //获取模板
        String context = getTemplateString(pageId);
        //静态化
        String html = getHtml(context,model);
        return html;
    }

    public ResponseResult post(String pageId){
        Optional<CmsPage> optional = cmsPageRepository.findById(pageId);
        if (!optional.isPresent()){
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
        //执行静态化
        String pageHtml = this.getPageHtml(pageId);
        //保存到fs中
        this.saveHtml(pageId,pageHtml);
        //发送信息
        this.postMessage(pageId);

        return new ResponseResult(CommonCode.SUCCESS);
    }

    private void postMessage(String pageId) {
        Optional<CmsPage> optional = cmsPageRepository.findById(pageId);
        if (!optional.isPresent()){
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
        CmsPage cmsPage = optional.get();
        Map map=new HashMap();
        map.put("pageId",pageId);
        String  str= JSON.toJSONString(map);
        String siteId = cmsPage.getSiteId();
        rabbitTemplate.convertAndSend(RabbitConfig.EX_ROUTING_CMS_POSTPAGE,siteId,str);
    }

    private CmsPage saveHtml(String pageId, String pageHtml) {
        Optional<CmsPage> optional = cmsPageRepository.findById(pageId);
        if (!optional.isPresent()){
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
        CmsPage cmsPage = optional.get();
        String htmlFileId = cmsPage.getHtmlFileId();
//        文件存在先删
        if (StringUtils.isNotEmpty(htmlFileId)){
            gridFsTemplate.delete(Query.query(Criteria.where("_id").is(htmlFileId)));
        }
        //保存文件到fs上
        try {
            InputStream inputStream = IOUtils.toInputStream(pageHtml, "utf-8");
            ObjectId objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());
            String fileId = objectId.toString();
            cmsPage.setHtmlFileId(fileId);
            cmsPageRepository.save(cmsPage);
            return cmsPage;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private String getHtml(String template, Map model) {
        try {
//        配置类
            Configuration configuration = new Configuration(Configuration.getVersion());
//        模板加载类
            StringTemplateLoader templateLoader = new StringTemplateLoader();
            templateLoader.putTemplate("template", template);
//        配置类加载模板加载类
            configuration.setTemplateLoader(templateLoader);

            Template template1 = configuration.getTemplate("template");
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template1, model);
            return html;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
        return null;
    }

    private String getTemplateString(String pageId) {
        CmsPageResult cmsPageResult = this.findById(pageId);
        if (cmsPageResult == null) {
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
        String templateId = cmsPageResult.getCmsPage().getTemplateId();
        if (templateId == null || templateId.length() == 0) {
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
        Optional<CmsTemplate> cmsTemplateOptional = cmsTemplateRepository.findById(templateId);
        if (!cmsTemplateOptional.isPresent()) {
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
        CmsTemplate cmsTemplate = cmsTemplateOptional.get();
        String templateFileId = cmsTemplate.getTemplateFileId();
        //取出模板内容
        GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));
//        打开下载流对象
        GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
//        GridFsResource 对象创建
        GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
        try {
            String context = IOUtils.toString(gridFsResource.getInputStream(), "utf-8");
            return context;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private Map getModel(String pageId) {
        //获取dataUrl
        CmsPageResult cmsPageResult = findById(pageId);
        if (cmsPageResult == null) {
            ExceptionCast.cast(CommonCode.INVALID_PARAM);
        }
        String dataUrl = cmsPageResult.getCmsPage().getDataUrl();
        if (dataUrl == null || dataUrl.length() == 0) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAURLISNULL);
        }
        //获取模型数据
        ResponseEntity<Map> forEntity = restTemplate.getForEntity(dataUrl, Map.class);
        Map body = forEntity.getBody();
        if (body == null) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
        if (body.get("model") == null) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
        return body;
    }



}
